<!DOCTYPE html>

<html>

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>waterfall 布局</title>
  <meta name="description" content="">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="">
  <style>
    .content {
      position: relative;
      border: 5px solid green;
      width: 100%;
      min-height: 600px;
    }

    .content div {
      position: absolute;
      border: 2px solid blue;
    }
  </style>
</head>

<body>
  <!-- 瀑布流，宽度一致，高度不一致 -->
  <div class="content" id="contentBox">

  </div>

  <script>
    // 封装使用waterfall.js




    /* 
     container  总容器
     rowMacNumber 每列多少个元素
     itemsList 要排列的div ,是一个数组
    */
    function waterfall(container, rowMaxNumber = 3, itemsList) {
      var total = 0;
      var container = container.nodeType ? container : document.querySelector(container);
      container.style.position = "relative";
      container.style.overflow = "scroll";
      var containerWidth = container.clientWidth;
      // rowItemWidth 在选择几列布局的时候就已经确定了
      var rowItemWidth = Math.floor(containerWidth / rowMaxNumber);

  
     // 用来判断是否存在img 异步加载内容
      var imgNum = 0;
      var loaded = 0;
      // 判断itemList 里面是否存在图片
     for(let i =0; i<itemsList.length;i++ ){
       if(itemsList[i] instanceof Image){
        itemsList[i].onload = function(){
          ++ loaded ;
          // 最慢的图片已经加载好了
          if(loaded == imgNum){
            render()
          }
        }
        imgNum ++;
       }
     }
    // 计算img 的数目
    function calcImgNum(){
      var imgNum = 0;
      for(let i =0; i<itemsList.length;i++ ){
       if(itemsList[i] instanceof Image){
        imgNum ++;
       }
     }  
     return imgNum;  
    }

    // 第二次渲染的逻辑不一样
    function secondRender(){
      // 此次新增的item
      var itemsAdd = itemsList.slice(imgNum, itemsList.length);
      for(let i = 0; i<itemsAdd.length;i++ ){
       if(itemsAdd[i] instanceof Image){
        imgNum ++;
        itemsAdd[i].onload = function(){
          loaded ++ ;
          // 最慢的图片已经加载好了
          if(loaded == imgNum){
            itemsAdd.forEach(item => {
              insertIntoContent(container, item)
            });
            
          }
        }
        
       }
     }

    }


    
    // 如果imgNum 存在不执行， 等最慢的图片加载完成后才执行渲染
      async function  render() {
        if(imgNum > 0 && imgNum !== loaded) return;
        if( calcImgNum()!== imgNum ){
          console.log("第二次渲染了");
          return secondRender();
        }
        container.innerHtml = '';
        for(let i = 0; i< itemsList.length; i++){
          insertIntoContent(container, itemsList[i])
        }
      }
     
      // 这里计算div 的高度是简历在 item 高度已知的情况下，但是异步的div可能高度是算不出来的
      function calcLastIndexTop(container) {
        if (total < rowMaxNumber) return 0;
        var lastIndex = total - rowMaxNumber
        // var lastRowIndexHeight = container.children[lastIndex].clientHeight + 2 * 2;
        var  lastRowItem =  container.children[lastIndex];
        // var lastRowIndexHeight= parseInt(getComputedStyle(lastRowItem ).height);
        var lastRowIndexHeight= parseInt(lastRowItem.getBoundingClientRect().height); 
        var lastRowIndexTop = parseInt(lastRowItem.style.top);
        return lastRowIndexTop + lastRowIndexHeight;
      }

      /*
         返回一个对象{left:"10px", top:"10px"}
      */
      function getCurrentLeftAndTop(container) {
        // 在行上的相对位置index 
        var presentRowIndex = total % rowMaxNumber;
        var left = presentRowIndex * rowItemWidth + "px";
        var top = calcLastIndexTop(container) + "px";
        return { left, top }
      }


      function insertIntoContent(container,item) {
        let { left, top } = getCurrentLeftAndTop(container);
        let box = createRowItem(item, rowItemWidth);
        box.style.left = left;
        box.style.top = top;

        container.appendChild(box);
        total++;
      }



      // 创建一个宽高随机的box div 模拟页面的不同区域部分
      function createRowItem(item, rowItemWidth = 100) {
        var box = document.createElement("div");
        box.style.position = "absolute";
        box.style.width = rowItemWidth + "px";
        box.style.overflow = "scroll";
        box.appendChild(item);
        return box;
      }

      return {
        render,
        itemsList,
        total
      }
    }
   /*
      使用 waterFall(container, rowMaxNumber = 3, itemsList)
      返回一个对象，这个对象有一个itemList 数组 和一个render 函数，
      后面需要添加div ,只需要往 itemList 里面添加div 然后render 一下即可重新渲染
    */

   var itemList = new Array(5).fill(5).map(()=>{
      var img = new Image();
         img.src="view.jpeg";
         return img;
    });
   var waterfallBox = waterfall("#contentBox", 3, itemList);
       waterfallBox.render();

       //模拟异步获得新的item 元素
       setTimeout(function(){
        var img = new Image();
         img.src="view.jpeg";
         var img2 = new Image();
         img2.src="shanghai.jpeg";
        itemList.push(img);
        itemList.push(img2);
       
        waterfallBox.render()
       },2000)

  </script>

</body>

</html>